// Copyright 2012 Google Inc. All Rights Reserved.

package com.google.appengine.preferencessync.internal.network;

import com.google.appengine.preferencessync.adapter.AbstractSyncablePrefsService.RequestProcessor;
import com.google.appengine.preferencessync.internal.Config;
import com.google.appengine.preferencessync.internal.InternalSyncException;
import com.google.appengine.preferencessync.internal.InternalSyncException.ExceptionType;
import com.google.appengine.preferencessync.internal.ResponsePaging;
import com.google.appengine.syncserver.shared.HttpParameterDefinitions.ClientRequest;
import com.google.appengine.syncserver.shared.PropertyChange;
import com.google.appengine.syncserver.shared.ReadUpdateRequest;
import com.google.appengine.syncserver.shared.ReadUpdateResponsePage;

import android.util.Log;

import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;

import java.io.IOException;
import java.util.ArrayList;

/**
 * Server changes cache.
 */
public class UpdatesFromServerCacher {
  // Store all the pages here.
  private final ResponsePaging paging = new ResponsePaging();

  // version to get changes from.
  private long currentReadStartVersion;

  // shared preference name.
  private final String preferencesName;
  private final Config config;

  private final RequestProcessor requestProcessor;

  /**
   * The default constructor.
   */
  public UpdatesFromServerCacher(Config config, String preferencesName, long serverHeadVersion,
      RequestProcessor requestProcessor) {
    this.preferencesName = preferencesName;
    this.config = config;
    this.currentReadStartVersion = serverHeadVersion;
    this.requestProcessor = requestProcessor;
  }

  /**
   * Resume caching preferences.
   * @throws InternalSyncException
   *
   * @returns headVersion at the server.
   */
  public long resumeCaching() throws InternalSyncException {
    ReadUpdateResponsePage response = null;
    do {
      // Get request starting from maxVersion + 1. maxVersion is
      ReadUpdateRequest request =
          new ReadUpdateRequest(config.getUsername(), preferencesName, config.getClientId(),
              config.getPagingSize(), currentReadStartVersion + 1);

      String responseStr = HttpUtils.sendRequest(requestProcessor, config.getRootUrl(),
          ClientRequest.READ_REQUEST, request.toString());

      Exception exception = null;
      try {
        response = ReadUpdateResponsePage.valueOf(responseStr);
      } catch (JsonParseException e) {
        exception = e;
      } catch (JsonMappingException e) {
        exception = e;
      } catch (IOException e) {
        exception = e;
      }

      if (exception != null) {
        throw new InternalSyncException(exception, ExceptionType.INTERNAL_EXCEPTION,
            exception.getMessage(), Log.ERROR);
      }

      currentReadStartVersion = response.getMaxVersion();
      paging.addChanges(response.getPreferenceChanges());
    } while (!response.isLastPage());
    return currentReadStartVersion;
  }

  public ArrayList<PropertyChange> getPropertyChanges() {
    return paging.getAllChanges();
  }

  public String getPreferencesName() {
    return preferencesName;
  }
}
